package com.aj.fingerbong.netty.transport;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * 数据传输
 */
public class TransportServer {

    private TransportServer() {
    }

    private static TransportServer INSTANCE = new TransportServer();

    public static TransportServer getInstance() {
        return INSTANCE;
    }

    /**
     * 检测内存泄漏的工具类ResourceLeakDetector,ByteBuf 都要被 ResourceLeakDetector 记录起来,主要是针对池化的ByteBuf
     * <p>
     * SIMPLE，默认等级，告诉我们取样的1%的ByteBuf是否发生了泄露，但总共一次只打印一次
     * DISABLED，禁用，完全禁止泄露检测，省点消耗  生产
     * ADVANCED，高级，告诉我们取样的1%的ByteBuf发生泄露的地方。每种类型的泄漏（创建的地方与访问路径一致）只打印一次,对性能有影响
     * PARANOID，偏执，跟高级选项类似，但此选项检测所有ByteBuf  测试时用
     */
    //ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
    public void start() throws InterruptedException {
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup workers = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, workers)
                    //初始化服务端可连接队列,指定了队列的大小
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //禁止使用Nagle算法（Nagle算法是将小的数据包组装为更大的帧然后进行发送）,即小数据即时传输
                    .option(ChannelOption.TCP_NODELAY, true)
                    //设置该选项以后，如果在两小时内没有数据的通信时，TCP会自动发送一个活动探测数据报文
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new StringEncoder()).addLast(new StringDecoder()).addLast(new DefaultTransportHandler());
                }
            });
            ChannelFuture future = bootstrap.bind(9999).sync();
            future.channel().closeFuture().sync();
        } finally {
            boss.shutdownGracefully();
            workers.shutdownGracefully();
        }
    }
}
